import pymysql

#1.连接数据库
# db= pymysql.connect(host='localhost',user='root',password='root',database='mysql')
import pandas as pd
from sqlalchemy import create_engine
import math

def csv_to_mysql_chunked(csv_file, host, user, password, database, table_name, chunk_size=10000):
    """
    分块导入大CSV文件到MySQL
    Args:
        csv_file: CSV文件路径
        host: MySQL主机地址
        user: MySQL用户名
        password: MySQL密码
        database: 数据库名
        table_name: 表名
        chunk_size: 每次处理的行数
    """

    # 1.创建用于连接数据库的引擎engine
    engine = create_engine(f'mysql+mysqlconnector://{user}:{password}@{host}/{database}')

    # 2.打开文件并计算总行数
    # 2.1. open(csv_file, 'r'):打开指定的CSV文件以供读取(返回一个文件对象，可以迭代文件中的每一行) # 加载文件(这段代码的作用是打开一个 CSV 文件并以只读模式进行访问。)
    # 2.2. for row in open(csv_file, 'r') :遍历文件对象，每次迭代获取文件中的一行内容(row 变量代表文件中的每一行)
    # 2.3. 1 for row in open(csv_file, 'r'): 这是一个生成器表达式(对于文件中的每一行，生成数字1)
    # 2.4.  sum(1 for row in open(csv_file, 'r')): sum() 函数计算生成器表达式产生的所有1的总和(实际效果是统计文件的总行数)
    # 2.5.举例子：# squares = [1 for x in range(10)] # print(squares)  # 结果[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    total_rows = sum(1 for row in open(csv_file, 'r',encoding="utf-8")) - 1  # 减去标题行#这段代码的作用是打开一个 CSV 文件并以只读模式进行访问。
    print(f"总行数: {total_rows}")

    # 3.按设定的数据块大小读取文件的数据并自动生成sql插入数据到mysql。(每次从文件中按照chunk_size设定的数据块行数每次读取chunk_size条数据构成一个data_fram<类似于一个虚拟表>)
    # 3.1.统计本案例累计操作的数据块包含的行数
    insert_row_count = 0 #用于累计统计每次读取的数据块包含的数据行数
    # read_csv()当指定 chunksize 参数时，函数会返回一个 迭代器 (iterator)，而不是一次性加载整个文件 #每次迭代时，会读取最多5000行数据到一个 DataFrame 中
    reader = pd.read_csv(csv_file, chunksize=chunk_size) #3.2.读取文件并获取迭代器对象reader # read_csv()是 pandas 库中的 read_csv 函数，用于读取CSV文件
    # 3.3.遍历迭代器中的每个元素(从迭代器中获取每个dataFrame)
    #  DataFrame，包含指定大小的数据块(类似于虚拟表)(本案例是包含csv文件3行数据的虚拟机)
    for data_frame in  reader:
        # 3.4.将迭代出的数据转化为sql并交给mysql去执行(追加方式插入数据，不插入data_frame的index)
        #'append' 表示追加数据到现有表中,   index=False：不将 DataFrame 的索引作为数据列插入到数据库中
        # (如果index的值是true则会给表中的index列自动插入数据(欧聪0开始)，如果没有此列会报错<而且每次插入都是从0开始，相当于给每次插入的数据行一个编号>)
        data_frame.to_sql(name=table_name, con=engine, if_exists='append', index=False) #index的值为false则不会给index列插入数据(有index列时只会给此列插入null值)
        # 3.5.  将虚拟表data_frame中的数据条数累加到insert_row_count变量中
        insert_row_count += len(data_frame)  # len(chunk) 是内置函数，用于获取chunk对象的长度
        print(f"已导入 {insert_row_count}/{total_rows} 行")

    print(f"成功导入 {insert_row_count} 行数据到 {table_name} 表中")





# 使用示例
csv_to_mysql_chunked(
    csv_file='C:\\ProgramData\\MySQL\\MySQL Server 9.4\\Uploads\\books.csv',   #   C:\ProgramData\MySQL\MySQL Server 9.4\Uploads\books.csv
    host='localhost',
    user='root',
    password='root',
    database='bookstore',
    table_name='books',
    chunk_size=5000
)



# 可选(本案例应该没用到)  pip install pymysql
# pip install sqlalchemy